function CheckParams_Model_20220926(parms)
% checks validity of inputs parameters

    SCALARS = {'b','beta','chi','gamma','Nx','Nz','NN','iota','eta',...
        'kappa','rho_x','x_bar','phi_match','OPTION_x_standardize_shock'};
    VECTORS_N = {'grid_N'};
    VECTORS_x = {'grid_x'};
    VECTORS_z = {'grid_z','s'};
    MATRICES = {'StateTransitionProbs','sigma_x'};
    ALL_FIELDS = [SCALARS,VECTORS_N,VECTORS_x,VECTORS_z,MATRICES];

    % 1. check required fields
    for n = 1:numel(ALL_FIELDS)
        if ~isfield(parms,ALL_FIELDS{n})
            error('Required field %s is not present.', ALL_FIELDS{n});
        end
    end

    % 2. check dimensions
    for n = 1:numel(SCALARS)
        if ~isscalar(parms.(SCALARS{n}))
            error('%s should be a scalar.', SCALARS{n})
        end
    end
    for n = 1:numel(VECTORS_N)
        if ~check_vector_dim(parms.(VECTORS_N{n}),parms.NN)
            error('%s should be a vector with %g elements.',...
                VECTORS_N{n},parms.NN);
        end
    end
    for n = 1:numel(VECTORS_x)
        if ~check_vector_dim(parms.(VECTORS_x{n}),parms.Nx)
            error('%s should be a vector with %g elements.',...
                VECTORS_x{n},parms.Nx);
        end
    end
    for n = 1:numel(VECTORS_z)
        if ~check_vector_dim(parms.(VECTORS_z{n}),parms.Nz)
            error('%s should be a vector with %g elements.',...
                VECTORS_z{n},parms.Nz);
        end
    end
    if ~check_matrix_dim(parms.StateTransitionProbs,parms.Nz,parms.Nz)
        error('StateTransitionProbs should be %g by %g.', parms.Nz, parms.Nz); 
    end
    if ~check_matrix_dim(parms.sigma_x,parms.NN,parms.Nz)
        error('sigma_x should be %g by %g.', parms.NN, parms.Nz); 
    end

    % 3. check parameter values
    if any(parms.StateTransitionProbs(:)<0) || ...
            any(abs(sum(parms.StateTransitionProbs,2)-1)>1e-10)
        error('StateTransitionProbs is not a valid transition matrix.');
    end

    STRICT_POS = {'b','beta','gamma','chi','Nz','Nx','NN','iota','s','kappa'};
    POS = {};
    NEG = {};
    BETWEEN_0_1_STRICT = {'eta','grid_N','rho_x'};
    BETWEEN_0_1 = {};

    for n = 1:numel(STRICT_POS)
        if ~check_lims(parms.(STRICT_POS{n}),0,Inf,true)
            error('%s should be strictly positive.',STRICT_POS{n});
        end
    end

    for n = 1:numel(POS)
        if ~check_lims(parms.(POS{n}),0,Inf,false)
            error('%s should be positive.',POS{n});
        end
    end
    
    for n = 1:numel(NEG)
        if ~check_lims(-parms.(NEG{n}),0,Inf,false)
            error('%s should be negative.',NEG{n});
        end
    end

    for n = 1:numel(BETWEEN_0_1_STRICT)
        if ~check_lims(parms.(BETWEEN_0_1_STRICT{n}),0,1,true)
            error('%s should be strictly between 0 and 1.', ...
                BETWEEN_0_1_STRICT{n});
        end
    end

    for n = 1:numel(BETWEEN_0_1)
        if ~check_lims(parms.(BETWEEN_0_1{n}),0,1,false)
            error('%s should be between 0 and 1.', ...
                BETWEEN_0_1{n});
        end
    end

    if any(diff(parms.grid_z)<=0)
        error('grid_z should be increasing');
    end

    diff_N = diff(parms.grid_N);
    if any(diff_N<=0) || max(diff_N) - min(diff_N)>=1e-10
        error('grid_N should be increasing and evenly spaced');
    end

    fprintf('parameters are okay.\n');

end

function TF = check_vector_dim(A,n)

    if ~isvector(A)
        TF = false;
    else
        TF = numel(A)==n;
    end

end

function TF = check_matrix_dim(A,dim1,dim2)
    
    SIZ = size(A);

    if numel(SIZ)~=2
        TF = false;
    else
        TF = (SIZ(1)==dim1) && (SIZ(2)==dim2);
    end

end

function TF = check_lims(A,lb,ub,is_strict_ineq)
% default: inequalities are not strict
    
    if nargin<4; is_strict_ineq = false; end

    if is_strict_ineq
        TF = all(A(:)>lb & A(:)<ub);
    else
        TF = all(A(:)>=lb & A(:)<=ub);
    end

end